package com.snail.snailvr.disk.box.fragments;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.PorterDuff;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.box.androidsdk.content.BoxApiFile;
import com.box.androidsdk.content.BoxException;
import com.box.androidsdk.content.models.BoxDownload;
import com.box.androidsdk.content.models.BoxFile;
import com.box.androidsdk.content.models.BoxFolder;
import com.box.androidsdk.content.models.BoxItem;
import com.box.androidsdk.content.models.BoxListItems;
import com.box.androidsdk.content.models.BoxSession;
import com.box.androidsdk.content.requests.BoxRequestsFile;
import com.snail.snailvr.R;
import com.snail.snailvr.disk.box.uidata.BoxListItem;
import com.snail.snailvr.disk.box.uidata.ThumbnailManager;
import com.snail.snailvr.network.providers.downloads.DownloadHelper;
import com.snail.snailvr.network.providers.downloads.DownloadManager;
import com.snail.snailvr.utils.Constant;
import com.snail.snailvr.utils.DatabaseUtils;
import com.snail.snailvr.utils.DialogUtils;
import com.snail.snailvr.utils.Extensions;
import com.snail.snailvr.utils.FileUtil;
import com.snail.snailvr.utils.LogUtils;
import com.snail.snailvr.utils.ToastUtils;
import com.snail.snailvr.utils.Util;
import com.snail.snailvr.widget.WrapContentLinearLayoutManager;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import butterknife.Bind;
import butterknife.ButterKnife;
import rx.Observable;
import rx.Single;
import rx.SingleSubscriber;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/**
 * A simple {@link Fragment} subclass.
 * Activities that contain this fragment must implement the
 * {@link BoxBrowseFragment.OnFragmentInteractionListener} interface
 * to handle interaction events.
 */
public abstract class BoxBrowseFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {

    public static final String ARG_ID = "argId";
    public static final String ARG_USER_ID = "argUserId";
    public static final String ARG_NAME = "argName";
    public static final String ARG_LIMIT = "argLimit";

    public static final String TAG = BoxBrowseFragment.class.getName();
    protected static final int DEFAULT_LIMIT = 1000;

    protected static final String ACTION_FETCHED_ITEMS = "BoxBrowseFragment_FetchedItems";
    protected static final String ACTION_FETCHED_INFO = "BoxBrowseFragment_FetchedInfo";
    protected static final String ACTION_DOWNLOADED_FILE_THUMBNAIL = "BoxBrowseFragment_DownloadedFileThumbnail";
    protected static final String EXTRA_SUCCESS = "BoxBrowseFragment_ArgSuccess";
    protected static final String EXTRA_EXCEPTION = "BoxBrowseFragment_ArgException";
    protected static final String EXTRA_ID = "BoxBrowseFragment_FolderId";
    protected static final String EXTRA_FILE_ID = "BoxBrowseFragment_FileId";
    protected static final String EXTRA_OFFSET = "BoxBrowseFragment_ArgOffset";
    protected static final String EXTRA_LIMIT = "BoxBrowseFragment_Limit";
    protected static final String EXTRA_FOLDER = "BoxBrowseFragment_Folder";
    protected static final String EXTRA_COLLECTION = "BoxBrowseFragment_Collection";
    private static final String EXTRA_TITLE = "BoxBrowseFragment.Title";
    private static final String EXTRA_CANCELED = "BoxBrowseFragment.Canceled";

    private static List<String> THUMBNAIL_MEDIA_EXTENSIONS = Arrays.asList("gif", "jpeg", "jpg", "bmp", "svg", "png", "tiff");

    protected String mUserId;
    protected BoxSession mSession;
    protected int mLimit = DEFAULT_LIMIT;

    private BoxListItems mBoxListItems;

    protected OnFragmentInteractionListener mListener;

    protected BoxItemAdapter mAdapter;
    protected RecyclerView mItemsView;
    protected ThumbnailManager mThumbnailManager;
    protected SwipeRefreshLayout mSwipeRefresh;

    protected LocalBroadcastManager mLocalBroadcastManager;
    private String mTitle;
    private boolean mWaitingForConnection;
    private boolean mIsConnected;

    private View loading;
    private int loading_visibility = View.VISIBLE;
    private View no_data;

    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(ACTION_DOWNLOADED_FILE_THUMBNAIL)) {
                onDownloadedThumbnail(intent);
            }
            else
            {
                // Handle response
                if (intent.getAction().equals(ACTION_FETCHED_INFO)) {
                    onInfoFetched(intent);
                }
                else if (intent.getAction().equals(ACTION_FETCHED_ITEMS)) {
                    onItemsFetched(intent);
                }
                // TODO

                // Remove refreshing icon
                if (mSwipeRefresh != null) {
                    mSwipeRefresh.setRefreshing(false);
                }
            }
        }
    };

    private BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
                ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
                mIsConnected = (networkInfo != null && networkInfo.isConnected());
                if (mWaitingForConnection && mIsConnected) {
                    mWaitingForConnection = false;
                    onRefresh();
                }
            }
        }
    };

    private static ThreadPoolExecutor mApiExecutor;
    private static ThreadPoolExecutor mThumbnailExecutor;

    protected ThreadPoolExecutor getApiExecutor() {
        if (mApiExecutor == null || mApiExecutor.isShutdown()) {
            mApiExecutor = new ThreadPoolExecutor(1, 1, 3600, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
        }
        return mApiExecutor;
    }

    /**
     * Executor that we will submit thumbnail tasks to.
     *
     * @return executor
     */
    protected ThreadPoolExecutor getThumbnailExecutor() {
        if (mThumbnailExecutor == null || mThumbnailExecutor.isShutdown()) {
            mThumbnailExecutor = new ThreadPoolExecutor(1, 10, 3600, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
        }
        return mThumbnailExecutor;
    }

    protected IntentFilter initializeIntentFilters() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_FETCHED_INFO);
        filter.addAction(ACTION_FETCHED_ITEMS);
        filter.addAction(ACTION_DOWNLOADED_FILE_THUMBNAIL);
        return filter;
    }

    public BoxBrowseFragment() {
        // Required empty public constructor
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Initialize broadcast managers
        mLocalBroadcastManager = LocalBroadcastManager.getInstance(getActivity());
        if (getArguments() != null) {
            mUserId = getArguments().getString(ARG_USER_ID);
            mThumbnailManager = initializeThumbnailManager();
            mUserId = getArguments().getString(ARG_USER_ID);
            mSession = new BoxSession(getActivity(), mUserId);
            mLimit = getArguments().getInt(ARG_LIMIT);
        }
        if (savedInstanceState != null) {
            setListItem((BoxListItems) savedInstanceState.getSerializable(EXTRA_COLLECTION));

        }
        setRetainInstance(true);
    }

    @Override
    public void onResume() {
        getActivity().registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
        mLocalBroadcastManager.registerReceiver(mBroadcastReceiver, initializeIntentFilters());
        super.onResume();
    }

    @Override
    public void onPause() {
        mLocalBroadcastManager.unregisterReceiver(mBroadcastReceiver);
        getActivity().unregisterReceiver(mConnectivityReceiver);
        super.onPause();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putSerializable(EXTRA_COLLECTION, mBoxListItems);
        outState.putSerializable(EXTRA_TITLE, mTitle);

        super.onSaveInstanceState(outState);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (savedInstanceState != null) {
            setToolbar(savedInstanceState.getString(EXTRA_TITLE));
        }
    }

    private ThumbnailManager initializeThumbnailManager() {
        try {
            return new ThumbnailManager(getActivity().getCacheDir());
        } catch (FileNotFoundException e) {
            return null;
        }
    }

    protected void setToolbar(String name) {

        // 初次进入，提示“All Files”
        if(name==null || "".equals(name)){
            mTitle = getResources().getString(R.string.all_files);
        }
        else {
            mTitle = name;
        }

        if (getActivity() != null && getActivity() instanceof AppCompatActivity)
        {
            ActionBar toolbar = ((AppCompatActivity) getActivity()).getSupportActionBar();
            if (toolbar != null)
            {
                toolbar.setTitle(mTitle);
            }
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View rootView = inflater.inflate(R.layout.box_browsesdk_fragment_browse, container, false);
        mSwipeRefresh = (SwipeRefreshLayout) rootView.findViewById(R.id.box_browsesdk_swipe_reresh);
        mSwipeRefresh.setOnRefreshListener(this);
        mSwipeRefresh.setColorSchemeResources(R.color.positive_normal_color);

        loading = rootView.findViewById(R.id.loading);
        loading.setVisibility(loading_visibility);

        no_data = rootView.findViewById(R.id.no_data);
        no_data.setVisibility(View.GONE);

        mItemsView = (RecyclerView) rootView.findViewById(R.id.box_browsesdk_items_recycler_view);
        mItemsView.setLayoutManager(new WrapContentLinearLayoutManager(getActivity()));

        mAdapter = new BoxItemAdapter();
        mItemsView.setAdapter(mAdapter);

        if (mBoxListItems == null)
        {
            mAdapter.add(new BoxListItem(fetchInfo(), ACTION_FETCHED_INFO));
        }
        else
        {
            displayBoxList(mBoxListItems);
        }

        return rootView;
    }

    protected void setListItem(final BoxListItems items) {
        mBoxListItems = items;
    }


    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnFragmentInteractionListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onRefresh() {
        mSwipeRefresh.setRefreshing(true);
        getApiExecutor().execute(fetchInfo());
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    protected void onInfoFetched(Intent intent) {
        onItemsFetched(intent);
    }

    /**
     * Fetch the first information relevant to this fragment or what should be used for refreshing.
     *
     * @return A FutureTask that is tasked with fetching the first information relevant to this fragment or what should be used for refreshing.
     */
    public abstract FutureTask<Intent> fetchInfo();

    /**
     * Handle showing a collection in the given intent.
     *
     * @param intent an intent that contains a collection in EXTRA_COLLECTION.
     */
    protected void onItemsFetched(Intent intent) {

        loading.setVisibility(View.GONE);
        loading_visibility = View.GONE;

        if (intent.getBooleanExtra(EXTRA_SUCCESS, true)) {
            // 成功
            BoxListItems list = (BoxListItems) intent.getSerializableExtra(EXTRA_COLLECTION);

            if(list==null || list.size()==0) {
                // 无数据
                no_data.setVisibility(View.VISIBLE);
                mSwipeRefresh.setVisibility(View.GONE);
            }
            else {
                // 有数据
                no_data.setVisibility(View.GONE);
                mSwipeRefresh.setVisibility(View.VISIBLE);
            }

            mAdapter.remove(intent.getAction());
        }
        else {

            // 失败条件下的逻辑 TODO
            mSwipeRefresh.setVisibility(View.VISIBLE);
            no_data.setVisibility(View.GONE);

            BoxListItem item = mAdapter.get(intent.getAction());

            if (item != null)
            {
                item.setIsError(true);

                if (intent.getAction().equals(ACTION_FETCHED_INFO))
                {
                    item.setTask(fetchInfo());
                }
                else if (intent.getAction().equals(ACTION_FETCHED_ITEMS))
                {
                    int limit = intent.getIntExtra(EXTRA_LIMIT, DEFAULT_LIMIT);
                    int offset = intent.getIntExtra(EXTRA_OFFSET, 0);

                    item.setTask(fetchItems(offset, limit));
                }

                mAdapter.update(intent.getAction());

            }
            checkConnectivity();
            return;
        }

        checkConnectivity();

        displayBoxList((BoxListItems) intent.getSerializableExtra(EXTRA_COLLECTION));

    }

    /**
     * Call on loading error and refresh if loss of connectivity is the suspect.
     */
    protected void checkConnectivity() {
        mWaitingForConnection = !mIsConnected;
    }
    /**
     * show in this fragment a box list of items.
     */
    protected void displayBoxList(final BoxListItems items) {
        FragmentActivity activity = getActivity();
        if (activity == null) {
            return;
        }
        // if we are trying to display the original list no need to add.
        if (items == mBoxListItems) {

            //  mBoxListItems.addAll(items);
            if (mAdapter.getItemCount() < 1) {
                mAdapter.addAll(items);
            }
        } else {
            if (mBoxListItems == null) {
                setListItem(items);
            }
            mBoxListItems.addAll(items);
            mAdapter.addAll(items);
        }

        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mAdapter.notifyDataSetChanged();
            }
        });

        if (items.fullSize() != null && mBoxListItems.size() < items.fullSize()) {
            // if not all entries were fetched add a task to fetch more items if user scrolls to last entry.
            mAdapter.add(new BoxListItem(fetchItems(mBoxListItems.size(), mLimit), ACTION_FETCHED_ITEMS));
        }

    }

    protected abstract FutureTask<Intent> fetchItems(final int offset, final int limit);

    /**
     * Handles showing new thumbnails after they have been downloaded.
     *
     * @param intent
     */
    protected void onDownloadedThumbnail(final Intent intent) {
        if (intent.getBooleanExtra(EXTRA_SUCCESS, false) && mAdapter != null) {
            mAdapter.update(intent.getStringExtra(EXTRA_FILE_ID));
        }
    }

    protected class BoxItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        BoxListItem mItem;

        View mView;

        @Bind(R.id.filePanel)
        View filePanel;

        @Bind(R.id.file_image)
        ImageView file_image;

        @Bind(R.id.file_name)
        TextView file_name;

        @Bind(R.id.file_size)
        TextView file_size;

        @Bind(R.id.file_download)
        ImageView file_download;

        @Bind(R.id.file_saved)
        TextView file_saved;

        @Bind(R.id.folderPanel)
        View folderPanel;

        @Bind(R.id.folder_name)
        TextView folder_name;

        public BoxItemViewHolder(View itemView) {
            super(itemView);

            itemView.setOnClickListener(this);

            mView = itemView;

            ButterKnife.bind(this, itemView);
        }

        public void bindItem(BoxListItem item) {
            mItem = item;

            onBindBoxItemViewHolder(this);
        }

        public void setError(BoxListItem item) {
            mItem = item;
            FragmentActivity activity = getActivity();
            if (activity == null) {
                return;
            }

            file_image.setVisibility(View.VISIBLE);
            file_size.setVisibility(View.VISIBLE);
            file_name.setText(activity.getResources().getString(R.string.box_browsesdk_error_retrieving_items));
            file_size.setText(activity.getResources().getString(R.string.box_browsesdk_tap_to_retry));
        }

        public void setLoading() {
            FragmentActivity activity = getActivity();
            if (activity == null) {
                return;
            }

            // loading中暂时隐藏视图
            filePanel.setVisibility(View.GONE);
            folderPanel.setVisibility(View.GONE);
        }

        public BoxListItem getItem() {
            return mItem;
        }

        public View getView() {
            return mView;
        }

        @Override
        public void onClick(View v) {
            if(mSwipeRefresh.isRefreshing()){
                return;
            }
            if (mItem == null) {
                return;
            }

            if (mItem.getIsError()) {
                mItem.setIsError(false);
                mApiExecutor.execute(mItem.getTask());
                setLoading();
            }

            if (mListener != null) {
                if (mListener.handleOnItemClick(mItem.getBoxItem()))
                {
                    FragmentActivity activity = getActivity();
                    if (activity == null) {
                        return;
                    }

                    if (mItem.getBoxItem() instanceof BoxFolder) {
                        BoxFolder folder = (BoxFolder) mItem.getBoxItem();
                        FragmentTransaction trans = activity.getSupportFragmentManager().beginTransaction();

                        // All fragments will always navigate into folders
                        com.snail.snailvr.disk.box.fragments.BoxBrowseFolderFragment browseFolderFragment = com.snail.snailvr.disk.box.fragments.BoxBrowseFolderFragment.newInstance(folder, mSession);
                        trans.replace(R.id.box_browsesdk_fragment_container, browseFolderFragment)
                                .addToBackStack(TAG)
                                .commit();
                    }
                }
            }
        }
    }

    protected class BoxItemAdapter extends RecyclerView.Adapter<BoxItemViewHolder> {

        protected ArrayList<BoxListItem> mListItems = new ArrayList<BoxListItem>();
        protected HashMap<String, BoxListItem> mItemsMap = new HashMap<String, BoxListItem>();

        @Override
        public BoxItemViewHolder onCreateViewHolder(ViewGroup viewGroup, int i)
        {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.net_disk_files_item, viewGroup, false);

            return new BoxItemViewHolder(view);
        }

        @Override
        public void onBindViewHolder(BoxItemViewHolder boxItemHolder, int i)
        {
            BoxListItem item = mListItems.get(i);

            if (item.getIsError())
            {
                boxItemHolder.setError(item);
                return;
            }
            else if (item.getType() == BoxListItem.TYPE_FUTURE_TASK)
            {
                getApiExecutor().execute(item.getTask());
                boxItemHolder.setLoading();
                return;
            }
            else
            {
                boxItemHolder.bindItem(item);

                // Fetch thumbnails for media file types
                if (item.getBoxItem() instanceof BoxFile && Extensions.isVideo(item.getBoxItem().getName()))
                {
                    if (item.getTask() == null )
                    {
                        item.setTask(downloadThumbnail(item.getBoxItem().getId(),
                                mThumbnailManager.getThumbnailForFile(item.getBoxItem().getId()), boxItemHolder));
                    }
                    else if (item.getTask().isDone())
                    {
                        try {
                            Intent intent = item.getTask().get();
                            boolean canceled = intent.getBooleanExtra(EXTRA_CANCELED, false);
                            if (intent.getBooleanExtra(EXTRA_SUCCESS, true) || canceled) {
                                // if we were unable to get this thumbnail for any reason besides a 404 try it again.
                                Object ex = intent.getSerializableExtra(EXTRA_EXCEPTION);
                                if (canceled || ex != null && ex instanceof BoxException && ((BoxException) ex).getResponseCode() != HttpURLConnection.HTTP_NOT_FOUND) {
                                    item.setTask(downloadThumbnail(item.getBoxItem().getId(),
                                            mThumbnailManager.getThumbnailForFile(item.getBoxItem().getId()), boxItemHolder));
                                }
                            }
                        } catch (Exception e) {
                            // e.printStackTrace();
                        }
                    }
                }
            }

            if (item.getTask() != null && !item.getTask().isDone()) {
                getThumbnailExecutor().execute(item.getTask());
            }
        }

        @Override
        public int getItemCount() {
            return mListItems.size();
        }

        public BoxListItem get(String id) {
            return mItemsMap.get(id);
        }

        public synchronized void removeAll() {
            mItemsMap.clear();
            mListItems.clear();
        }

        public void remove(BoxListItem listItem) {
            remove(listItem.getIdentifier());
        }

        public synchronized void remove(String key) {
            BoxListItem item = mItemsMap.remove(key);
            if (item != null) {
                boolean success = mListItems.remove(item);
            }
        }

        public void addAll(BoxListItems items) {
            for (BoxItem item : items) {
                if (!mItemsMap.containsKey(item.getId())) {
                    add(new BoxListItem(item, item.getId()));
                } else {
                    // update an existing item if it exists.
                    mItemsMap.get(item.getId()).setBoxItem(item);
                }
            }
        }

        public synchronized void add(BoxListItem listItem) {
            if (listItem.getBoxItem() != null) {
                // If the item should not be visible, skip adding the item
                if (!isItemVisible(listItem.getBoxItem())) {
                    return;
                }

                listItem.setIsEnabled(isItemEnabled(listItem.getBoxItem()));
            }

            mListItems.add(listItem);

            mItemsMap.put(listItem.getIdentifier(), listItem);

        }

        public void update(String id) {
            BoxListItem item = mItemsMap.get(id);
            if (item != null) {
                int index = mListItems.indexOf(item);
                // notifyItemChanged(index); 更换刷新方法，修复界面的闪烁问题
                notifyDataSetChanged();
            }
        }
    }

    /**
     * This interface must be implemented by activities that contain this
     * fragment to allow an item being tapped to be communicated to the activity
     */
    public interface OnFragmentInteractionListener {

        /**
         * Called whenever an item in the RecyclerView is clicked
         *
         * @param item the item that was clicked
         * @return whether the click event should continue to be handled by the fragment
         */
        boolean handleOnItemClick(BoxItem item);
    }

    /**
     * Called when a {@link com.snail.snailvr.disk.box.uidata.BoxListItem} is bound to a ViewHolder. Customizations of UI elements
     * should be done by overriding this method. If extending from a {@link com.snail.snailvr.disk.box.activities.BoxBrowseActivity}
     * a custom BoxBrowseFolder fragment can be returned in
     * {@link com.snail.snailvr.disk.box.activities.BoxBrowseActivity#createBrowseFolderFragment(BoxItem, BoxSession)}
     *
     * @param holder the BoxItemHolder
     */
    protected void onBindBoxItemViewHolder(final BoxItemViewHolder holder) {

        if (holder.getItem() == null || holder.getItem().getBoxItem() == null) {
            return;
        }

        final BoxItem item = holder.getItem().getBoxItem();

        if(item instanceof BoxFile) {// 文件

            holder.filePanel.setVisibility(View.VISIBLE);
            holder.folderPanel.setVisibility(View.GONE);

            holder.file_name.setText(item.getName());

            // 判断该文件是否已经下载
            File dir = DownloadManager.createDownloadDirIfNotExist();
            File target = new File(dir, item.getName());

            if (target.exists()) {
                holder.file_saved.setVisibility(View.VISIBLE);
            }
            else{
                holder.file_saved.setVisibility(View.GONE);
            }

            String size = item.getSize() != null ? FileUtil.formatShortFileSize(getActivity(), item.getSize()) : "";

            mThumbnailManager.setThumbnailIntoView(holder.file_image, item);

            holder.file_size.setText(size);

            holder.file_download.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // 开始下载
                    preDownloadFile((BoxFile) item, holder);
                }
            });
        }
        else if(item instanceof BoxFolder) {// 文件夹
            holder.folderPanel.setVisibility(View.VISIBLE);
            holder.filePanel.setVisibility(View.GONE);
            holder.folder_name.setText(item.getName());
        }
        else {
            //do nothing
        }
    }

    private void preDownloadFile(final BoxFile file, final BoxItemViewHolder holder)
    {
        File dir = DownloadManager.createDownloadDirIfNotExist();
        File target = new File(dir, file.getName());

        if ( target.exists() ){// 文件已经存在
            DialogUtils.showBasicDialog(getActivity(), getActivity().getResources().getString(R.string.video_added),
                    getActivity().getResources().getString(R.string.download_again), getActivity().getResources().getString(R.string.cancel),
                    getActivity().getResources().getString(R.string.DOWNLOAD), false, new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            holder.file_download.setImageResource(R.drawable.downloading);
                            ((AnimationDrawable) holder.file_download.getDrawable()).start();

                            downloadFile(file, holder, true);
                        }
                    });
        }
        else{// 文件不存在

            // 下载前开启动画
            holder.file_download.setImageResource(R.drawable.downloading);
            ((AnimationDrawable) holder.file_download.getDrawable()).start();

            downloadFile(file, holder, false);
        }
    }

    private void downloadFile(final BoxFile originFile, final BoxItemViewHolder holder, final boolean fileExist)
    {
        // 给出提示
        ToastUtils.makeToastColorShow(getActivity(), holder.mView, getActivity().getResources().getString(R.string.downloading));

        // 处理索引
        DatabaseUtils.getFileIndex(originFile.getName(), new SingleSubscriber<Integer>() {
            @Override
            public void onSuccess(Integer value) {
                String new_name = "";

                int current_file_index = value;

                if (current_file_index == -1) {
                    // 数据库无记录
                    // 不需要重命名
                    current_file_index++;
                    new_name = originFile.getName();
                }
                else {
                    // 有记录
                    if(fileExist) {
                        current_file_index++;
                        new_name = Util.getRepeatFileName(originFile.getName(), current_file_index);
                    }
                    else{
                        // 实际文件被删除，补位下载
                        new_name = originFile.getName();
                    }
                }

                // 开始下载后，将记录保存至数据库
                DatabaseUtils.saveFileIndex(originFile.getName(), current_file_index);

                startDownloadThread(originFile, new_name, new SingleSubscriber<File>() {
                    @Override
                    public void onSuccess(File value) {
                        File info = value;
                        LogUtils.d("download success");

                        holder.file_download.setAlpha(0.0f);
                        holder.file_download.setImageResource(R.drawable.ic_net_disk_download_finish);
                        holder.file_download.animate().alpha(1.0f).setDuration(Constant.NETDISK_ANIM_DURATION).start();

                        if (holder.file_saved.getVisibility() == View.GONE)
                        {
                            holder.file_saved.setVisibility(View.VISIBLE);
                        }

                        Observable.timer(2, TimeUnit.SECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<Long>() {
                            @Override
                            public void onCompleted() {
                                // 更新UI
                                holder.file_download.setAlpha(0.0f);
                                holder.file_download.setImageResource(R.drawable.ic_net_disk_download_normal);
                                holder.file_download.animate().alpha(1.0f).setDuration(Constant.NETDISK_ANIM_DURATION).start();
                            }

                            @Override
                            public void onError(Throwable e) {
                            }

                            @Override
                            public void onNext(Long aLong) {
                            }
                        });

                        DownloadHelper.addNewTransferVideoTask(info.getName(), info.getPath());
                    }

                    @Override
                    public void onError(Throwable error) {
                        // 异常情况处理
                        ToastUtils.makeToastColorShow(getActivity(), holder.mView, getActivity().getResources().getString(R.string.error_occurred));

                        holder.file_download.setAlpha(0.0f);
                        holder.file_download.setImageResource(R.drawable.ic_net_disk_download_normal);
                        holder.file_download.animate().alpha(1.0f).setDuration(Constant.NETDISK_ANIM_DURATION).start();
                    }
                });
            }

            @Override
            public void onError(Throwable error) {
                // 异常情况处理
                holder.file_download.setAlpha(0.0f);
                holder.file_download.setImageResource(R.drawable.ic_net_disk_download_normal);
                holder.file_download.animate().alpha(1.0f).setDuration(Constant.NETDISK_ANIM_DURATION).start();
            }
        });
    }

    private Subscription startDownloadThread(final BoxFile originFile, final String new_name, final SingleSubscriber subscriber) {

        return Single.create(new Single.OnSubscribe<File>() {
            @Override
            public void call(SingleSubscriber<? super File> singleSubscriber) {

                File downloadDir = DownloadManager.createDownloadDirIfNotExist();

                File targetFile = new File(downloadDir, new_name);

                File tmpFile = new File(downloadDir, new_name + ".tmp");

                if (tmpFile.exists()) {
                    tmpFile.delete();
                }
                try {
                    tmpFile.createNewFile();
                }
                catch (IOException e) {
                    singleSubscriber.onError(new Throwable("IOException"));
                }

                BoxApiFile api = new BoxApiFile(mSession);

                try {

                    BoxRequestsFile.DownloadFile request = api.getDownloadRequest(tmpFile, originFile.getId());

                    final BoxDownload downloadFileInfo = request.send();

                    LogUtils.d("Success");

                    if (tmpFile.renameTo(targetFile)) {
                        singleSubscriber.onSuccess(targetFile);
                    }
                    else{
                        singleSubscriber.onError(new Throwable("Rename Exception"));
                    }

                } catch (BoxException e) {
                    LogUtils.d("BoxException");
                    singleSubscriber.onError(new Throwable("BoxException"));
                } catch (IOException e) {
                    LogUtils.d("IOException");
                    singleSubscriber.onError(new Throwable("IOException"));
                }
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(subscriber);
    }

    /**
     * Defines the conditions for when a BoxItem should be shown as enabled
     *
     * @param item the BoxItem that should be enabled or not
     * @return whether or not the BoxItem should be enabled
     */
      public boolean isItemEnabled (BoxItem item){
            return true;
      }

      /**
      * Defines the conditions for when a BoxItem should be shown in the adapter
      * @param item the BoxItem that should be visible or not
      * @return whether or not the BoxItem should be visible
      */

      public boolean isItemVisible(BoxItem item) {
          return true;
      }

      /**
      * Download the thumbnail for a given file.

      * @param fileId file id to download thumbnail for.
      * @return A FutureTask that is tasked with fetching information on the given folder.
      */
      private FutureTask<Intent> downloadThumbnail(final String fileId, final File downloadLocation, final BoxItemViewHolder holder) {
           return new FutureTask<Intent>(new Callable<Intent>() {

                @Override
                public Intent call() throws Exception {
                    Intent intent = new Intent();
                    intent.setAction(ACTION_DOWNLOADED_FILE_THUMBNAIL);
                    intent.putExtra(EXTRA_FILE_ID, fileId);
                        intent.putExtra(EXTRA_SUCCESS, false);
                        try {
                            // no need to continue downloading thumbnail if we already have a thumbnail
                            if (downloadLocation.exists() && downloadLocation.length() > 0) {
                                intent.putExtra(EXTRA_SUCCESS, true);
                                return intent;
                            }
                            // no need to continue downloading thumbnail if we are not viewing this thumbnail.
                            if (holder.getItem() == null || holder.getItem().getBoxItem() == null || !(holder.getItem().getBoxItem() instanceof BoxFile)
                                    || !holder.getItem().getBoxItem().getId().equals(fileId)) {
                                intent.putExtra(EXTRA_SUCCESS, false);
                                intent.putExtra(EXTRA_CANCELED, true);
                                return intent;
                            }

                            BoxApiFile api = new BoxApiFile(mSession);
                            DisplayMetrics metrics = getResources().getDisplayMetrics();
                            int thumbSize = BoxRequestsFile.DownloadThumbnail.SIZE_128;
                            if (metrics.density <= DisplayMetrics.DENSITY_MEDIUM) {
                                thumbSize = BoxRequestsFile.DownloadThumbnail.SIZE_64;
                            } else if (metrics.density <= DisplayMetrics.DENSITY_HIGH) {
                                thumbSize = BoxRequestsFile.DownloadThumbnail.SIZE_64;
                            }
                            api.getDownloadThumbnailRequest(downloadLocation, fileId)
                                    .setMinHeight(thumbSize)
                                    .setMinWidth(thumbSize)
                                    .send();
                            if (downloadLocation.exists()) {
                                intent.putExtra(EXTRA_SUCCESS, true);
                            }
                        } catch (BoxException e) {
                            intent.putExtra(EXTRA_SUCCESS, false);
                            intent.putExtra(EXTRA_EXCEPTION, e);
                        } finally {
                            mLocalBroadcastManager.sendBroadcast(intent);
                        }

                        return intent;
                    }
                });
            }

      /**
      * Java version of routine to turn a long into a short user readable string.
      * <p/>
             * This routine is used if the JNI native C version is not available.
             *
             * @param numSize the number of bytes in the file.
             * @return String Short human readable String e.g. 2.5 MB
             */
            private String localFileSizeToDisplay(final double numSize) {
                final int constKB = 1024;
                final int constMB = constKB * constKB;
                final int constGB = constMB * constKB;
                final double floatKB = 1024.0f;
                final double floatMB = floatKB * floatKB;
                final double floatGB = floatMB * floatKB;
                final String BYTES = "B";
                String textSize = "0 bytes";
                String strSize = Double.toString(numSize);
                double size;

                if (numSize < constKB) {
                    textSize = strSize + " " + BYTES;
                } else if ((numSize >= constKB) && (numSize < constMB)) {
                    size = numSize / floatKB;
                    textSize = String.format(Locale.ENGLISH, "%4.1f KB", size);
                } else if ((numSize >= constMB) && (numSize < constGB)) {
                    size = numSize / floatMB;
                    textSize = String.format(Locale.ENGLISH, "%4.1f MB", size);
                } else if (numSize >= constGB) {
                    size = numSize / floatGB;
                    textSize = String.format(Locale.ENGLISH, "%4.1f GB", size);
                }
                return textSize;
            }

            public static void setAccentColor(Resources res, ProgressBar progressBar) {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                    int accentColor = res.getColor(R.color.box_accent);
                    Drawable drawable = progressBar.getIndeterminateDrawable();
                    if (drawable != null) {
                        drawable.setColorFilter(accentColor, PorterDuff.Mode.SRC_IN);
                        drawable.invalidateSelf();
                    }
                }
      }
}